using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

using Publicuse.Util;
using Microsoft.AspNetCore.Http;
using Geekeradmin.Authorize;
using Publicuse.Cache;
using Publicuse.Entity;

namespace Geekeradmin.Authorize
{
    /// <summary>
    ///  用户是否登录以及操作权限验证
    /// </summary>
    /// <typeparam name="TRequirement"></typeparam>
    /// <typeparam name="TAttribute"></typeparam>
    public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> :
        AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
    {

        /// <summary>
        /// HandleRequirementAsync
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        /// <returns></returns>
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
        {
            var attributes = new List<TAttribute>();

            if ((context.Resource as AuthorizationFilterContext)?.ActionDescriptor is ControllerActionDescriptor action)
            {
                attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
                attributes.AddRange(GetAttributes(action.MethodInfo));
            }

            return HandleRequirementAsync(context, requirement, attributes);
        }

        /// <summary>
        /// HandleRequirementAsync
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        /// <param name="attributes"></param>
        /// <returns></returns>
        protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement,
                IEnumerable<TAttribute> attributes);

        private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
        {
            return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
        }
    }

    /// <summary>
    /// 用户是否登录以及操作权限验证
    /// </summary>
    internal class UserAuthorizationHandler : AttributeAuthorizationHandler<UserAuthorizationRequirement, UserAuthorizeAttribute>
    {
        private static Dictionary<string, string> exportlist = new Dictionary<string, string>();

        private readonly IHttpContextAccessor _httpContextAccessor;
        public UserAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
            UserAuthorizationRequirement requirement, IEnumerable<UserAuthorizeAttribute> attributes)
        {
            var httpContext = HttpContextExtendBase.Current;
            CommonResult result = new CommonResult();
            string accessright = httpContext.Request.Headers["accessright"];
            string api = httpContext.Request.Headers["api"];
            string jwttoken = httpContext.Request.Headers["token"];
            if (string.IsNullOrWhiteSpace(jwttoken))
            {
                if(string.IsNullOrEmpty(accessright) && string.IsNullOrEmpty(api)&& string.IsNullOrEmpty(jwttoken))
                {
                    context.Succeed(requirement);
                    return Task.CompletedTask;
                }

                result.code = -1;
                result.msg = ImplementResult.IDTokenEmpty.GetRemark();
                return HandleBlockedAsync(context, requirement, result, httpContext);
            }
            JwtToken token = new JwtToken();
            LoginCache.GetLoginCache.GetJwtToken(jwttoken,out token);
            if (token == null)
            {
                result.code = -1;
                result.msg = ImplementResult.IDTokenEmpty.GetRemark();
                return HandleBlockedAsync(context, requirement, result, httpContext);
            }
            var isTimeout = LoginCache.GetLoginCache.isTimeout(jwttoken,token);
            if (isTimeout)
            {
                result.code = (int)ImplementResult.UserLoginTimeOut;
                result.msg = ImplementResult.UserLoginTimeOut.GetRemark();
                return HandleBlockedAsync(context, requirement, result, httpContext);
            }
            var loginCode = token.uCode;
            var ep = httpContext.Request.Path.Value;
            if (ep.Contains("Export") && loginCode == null )
            {
                string exportTime = string.Empty;
                if (exportlist.TryGetValue(ep, out exportTime))
                {
                    context.Succeed(requirement);
                    return Task.CompletedTask;
                }
            }

          
            if (!string.IsNullOrEmpty(loginCode))
            {
                var apilength = api.Split('/');
                if (apilength.Length == 6)
                {
                    api = apilength[3] + "/" + apilength[4] + "/" + apilength[5];
                }
                var AppID = UserAuthorizeAttribute.AppID;
                var havepri = true;
                if (string.Compare(AppID, "noinspect", true) != 0)
                {
                    havepri=LoginCache.GetLoginCache.HaveMenu(loginCode,api);
                }
                if (havepri)
                {
                    if (api.Contains("Export"))
                    {
                        if (!exportlist.ContainsKey("/" + api))
                        {
                            exportlist.Add("/" + api, DateTime.Now.ToString("yyyyMMddHHmmss"));
                        }
                        else
                        {
                            exportlist.Remove("/" + api);
                            exportlist.Add("/" + api, DateTime.Now.ToString("yyyyMMddHHmmss"));
                        }                    
                        result.msg = "导出Excel检查完毕！";
                        result.code = 3000;
                        return HandleBlockedAsync(context, requirement, result, httpContext);
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(accessright))
                        {
                            result.code = -4;
                            result.msg = ImplementResult.Nopermission.GetRemark();
                            return HandleBlockedAsync(context, requirement, result, httpContext);
                        }
                        else
                        {
                            accessright = EnDecryptionUtil.DESDecryptb(accessright);
                            if (string.Compare(accessright, AppSettingUtil.SystemKey, true) != 0)
                            {
                                result.code = -4;
                                result.msg = ImplementResult.Nopermission.GetRemark();
                                return HandleBlockedAsync(context, requirement, result, httpContext);
                            }
                        }
                        context.Succeed(requirement);
                        return Task.CompletedTask;
                    }
                }
                else
                {
                    result.code = (int)ImplementResult.Nopermissiontooperate;
                    result.msg = ImplementResult.Nopermissiontooperate.GetRemark();
                    return HandleBlockedAsync(context, requirement, result, httpContext);
                }
            }
            else
            {
                result.msg = ImplementResult.UserLoginTimeOut.GetRemark();
                result.code = -1;
                return HandleBlockedAsync(context, requirement, result, httpContext);
            }
        }

        private Task HandleBlockedAsync(AuthorizationHandlerContext context, UserAuthorizationRequirement requirement, CommonResult errorMsg, HttpContext httpContext)
        {
            context.Succeed(requirement);
            httpContext.Response.Redirect("/api/Authority/Fail");
            HandleBlockedResult.result = errorMsg;
            return Task.CompletedTask;
        }
    }

    public class HandleBlockedResult
    {
        public static CommonResult result { get; set; }
    }
}
